#ifdef IMAM_LOG
#ifndef LOGSYS_FLAG
#define LOGSYS_FLAG
#endif
#endif

#include <project.h>
#define CITI_C

#include <sizes.h>
#include <aclconio.h>
#include <stdio.h>
#include <stdlib.h>
#include <svctxo.h>
#include <ctype.h>   
#include <acldev.h>
#include <aclstr.h>
#include <aclutil.h>
#include <prot8583.h>
#include <define.h>
#include <transact.h>
#include <dbmgr.h>
#include <mdlfuncs.h>
#include <svc.h>
#include <power.h>
#include <message.h>

#include <entry.h>    
#include <pinpad.h>   
#include <protocol.h>
#include <packet.h>
#include <tran.h>
#include <comm.h>
#include <modem.h>
#include <ppt.h>
#include <piputl.h>
#include <pipmsg.h>
#include <isoutl.h>
#include <isoload.h>
#include <ifldtbl.h>
#include <msg.h>
#include <msgfuncs.h>
#include <bdt.h>
#include <hdt.h>
#include <trt.h>
#include <mht.h>
#include <iit.h>
#include <accum.h>
#include <form.h>
#include <date.h>
#include <mem.h>
#include <spdebug.h>
#include <funcids.h>
#include <pbatch.h>
#include <errno.h>
#include <ascii.h>
#include <amexhost.h>
#include <pct.h>
#include <formater.h>
#include <table.h>
#include <string.h>
#include <confio.h>
#include <aclfile.h>
#include <format.h>
#include <spamsg.h>
#include <oper.h>
#include <batmsg.h>
#include <ui.h>
#include <tct.h>
#include <multilng.h>
#include <logo.h>
#include <settlbat.h>
#include <msgclrk.h>
#include <msgshf.h>
#include <menufunc.h>
#include <mit.h>
#include <applidl.h>
#include <tblutil.h>
#include <menus.h>
#include <Validt.h>
#include <stats.h>
#include <cardmsg.h>
#include <card.h>
#include <msg.h>
#include <define.h>
#include <entry.h>
#include <pinpad.h>
#include <ctype.h>
#include <gds.h>
#include <power.h>
#include <tip.h>
#include <iso8583.h>
#include <beetle.h>
#include <xmodem.h>
#include <modemmsg.h>
#include <scdefine.h>
#include <rcptsegs.h>
#include <operate.h>
#include <cdt.h>///ivan
#include <battery.h>
#include <printer.h>
#include <rs232.h>
#include <ConfProto.h> //

#ifdef __arm
#include <svc_sec.h>    //for aes ENCRYPTION
#endif

#ifndef ASC8X21_VFT
#define ASC8X21_VFT			"F:ASC8X21.VFT"
#endif

#include "IMAMids.h"
#include "MiniAtm.h"
#include "UclCode.h"
#include "ImamUtil.h"
#include "ImamMenu.h"

#include "..\cpacsrc\cpacmsg.h"
#include "..\cpacsrc\cpacids.h"
#include "..\cpacsrc\cpacsrc.h"
#include "..\cpacsrc\cpac.h"
#include "..\cpacsrc\cpacsize.h"
#include "..\cpacsrc\cpacprnt.h"
#include "..\cpacsrc\cpacoper.h"

#include "..\CITIsrc\CITImsg.h"
#include "..\CITIsrc\CITIsrc.h"
#include "..\CITIsrc\CITIids.h"
#include "..\CITIsrc\CITIsize.h"

//#include "..\EPPSrc\EPPSrc.h"
//#include "..\CASHSrc\CASHSrc.h"
//#include "..\CABKSrc\CABKSrc.h"

#include "..\EMVSrc\EMVsrcdef.h"

extern int	inMAMAvailable;  //
extern VS_BOOL fDisplayIdleMenu;  //
extern int inImamUnlockKeyboard;  // Add
extern int inImamModemLowPower;
extern unsigned long lnGlobalAmount;
extern int inImamTerminalModel;
extern int inImamLineNumber;
extern SMenu *ImamActiveMenu;
extern char szImamEnterPinLabel[22];
extern char szImamPAN[PAN_SIZE+1];
extern int inDisplayResponseMode;

extern TRANSACTION_BITMAP obTranMapCurr;

extern int inImamLineNumber;

int fSSL(void)
{
   inLoadPCLRec(0);
   if (inGetImamEncryptType()==2) return 1;
   return 0;
}

int fAES(void) 
{
   inLoadPCLRec(0);
   if (inGetImamEncryptType()==1) return 1;
   return 0;
}

#ifdef __arm
int inImamAesEncrypt (unsigned char *ucInput, int inInputLen, unsigned char *ucOutput, int *inOutputLen)
{
	unsigned char AesKey[33];  //for 16 byte key, 128 bit
	int inBlockNum = inInputLen/16;
	int i = 0;
	int inRetval;

	memset(AesKey, 0x00, sizeof(AesKey));
	memcpy(AesKey, "\xE4\x46\xEF\x0D\xAD\xAF\xC3\xA0\xB8\x66\x79\x51\x8D\x18\x72\xF7", 16);

	LOG_PRINTFF((0x08L, "INPUT LEN [%d]", inInputLen));
	if (inInputLen%16) {
		LOG_PRINTFF((0x08L, "INPUT LEN % 16 = [%d]", (inInputLen%16)));
		inBlockNum++;
		ucInput[inBlockNum*16-1] = inBlockNum*16 - inInputLen;
	} else {
		LOG_PRINTFF((0x08L, "INPUT LEN HABIS DIBAGI 16"));
		inBlockNum++;
		ucInput[inBlockNum*16-1] = inBlockNum*16 - inInputLen;
	}

	for (i=0; i<inBlockNum; i++) {
		inRetval = AES(AES128E, AesKey, &ucInput[i*16], &ucOutput[i*16]);
	}
    *inOutputLen = inBlockNum * 16;
	return inRetval;
}

int inImamAesDecrypt (unsigned char *ucInput, int inInputLen, unsigned char *ucOutput, int *inOutputLen)
{
	unsigned char AesKey[33];  //for 16 byte key, 128 bit
	int inBlockNum = inInputLen/16;
	int i = 0;
	int inRetval;

	memset(AesKey, 0x00, sizeof(AesKey));
	memcpy(AesKey, "\xE4\x46\xEF\x0D\xAD\xAF\xC3\xA0\xB8\x66\x79\x51\x8D\x18\x72\xF7", 16);
	
	if (inInputLen%16) inBlockNum++;

	for (i=0; i<inBlockNum; i++) {
		inRetval = AES(AES128D, AesKey, &ucInput[i*16], &ucOutput[i*16]);
	}
    *inOutputLen = inBlockNum * 16;
	return inRetval;
}
#endif

#ifndef __arm
int inAES_Encrypt (char *szData, int inDataLen)
{
#ifdef IMAM_AES_OMNI
	LIBENCRYPT cl;
	unsigned char abtKey[32];
	unsigned char szEncData[TLE_MAX_DATA_SZ];
	int iKeyLen = 0;
	int inEncDataLen = TLE_MAX_DATA_SZ;
	int iRet = 0;
	
	// Initialize AES library
	AES_Init(MODE_ECB, PAD_NULL_NUM_BYTES, &cl);
	iKeyLen = AES_KEY_LENGTH;
	// Generate Key
	memset(abtKey, 0x00, sizeof(abtKey));
	AES_GenKey ("1234567890123456", abtKey, &iKeyLen);
	LOG_PRINT_HEX(abtKey, iKeyLen);

	// encrypt data
	memset(szEncData, 0x00, sizeof(szEncData));
	iRet = cl.iEncrypt ((unsigned char *)szData, inDataLen, szEncData, &inEncDataLen, abtKey, AES_KEY_LENGTH, &cl);

	if (0 != iRet)
		return 0;  //encrypt err

	LOG_PRINT_HEX(szEncData, inEncDataLen);	
#endif
	return 1;
}

int inAES_Decrypt (char *szEncData, int inEncDataLen)
{
#ifdef IMAM_AES_OMNI
	LIBENCRYPT cl;
	unsigned char abtKey[32];
	unsigned char szPlainData[TLE_MAX_DATA_SZ];
	int iKeyLen = 0;
	int inPlainDataLen = TLE_MAX_DATA_SZ;
	int iRet = 0;
	
	// Initialize AES library
	AES_Init(MODE_ECB, PAD_NULL_NUM_BYTES, &cl);
	iKeyLen = AES_KEY_LENGTH;
	// Generate Key
	memset(abtKey, 0x00, sizeof(abtKey));
	AES_GenKey ("1234567890123456", abtKey, &iKeyLen);
	LOG_PRINT_HEX(abtKey, iKeyLen);

	// decrypt data
	memset(szPlainData, 0x00, TLE_MAX_DATA_SZ);
	iRet = cl.iDecrypt ((unsigned char *)szEncData, inEncDataLen, szPlainData, &inPlainDataLen, abtKey, AES_KEY_LENGTH, &cl);
	
	if (0 != iRet)
		return 0;

	LOG_PRINT_HEX(szPlainData, inPlainDataLen);	
#endif
	return 1;
}

int inImamAesEncrypt (unsigned char *ucInput, int inInputLen, unsigned char *ucOutput, int *inOutputLen)
{
#ifdef IMAM_AES_OMNI
	LIBENCRYPT cl;
	unsigned char abtKey[32];
	unsigned char szEncData[TLE_MAX_DATA_SZ];
	int iKeyLen = 0;
	int inEncDataLen = TLE_MAX_DATA_SZ;
	int iRet = 0;
	
	// Initialize AES library
	AES_Init(MODE_ECB, PAD_NULL_NUM_BYTES, &cl);
	iKeyLen = AES_KEY_LENGTH;
	// Generate Key
	memset(abtKey, 0x00, sizeof(abtKey));
	AES_GenKey ("1234567890123456", abtKey, &iKeyLen);
	LOG_PRINT_HEX(abtKey, iKeyLen);

	// encrypt data
	memset(szEncData, 0x00, sizeof(szEncData));
	iRet = cl.iEncrypt ((unsigned char *)ucInput, inInputLen, szEncData, &inEncDataLen, abtKey, AES_KEY_LENGTH, &cl);

	memcpy(ucOutput, szEncData, inEncDataLen);
	*inOutputLen = inEncDataLen;

	if (0 != iRet)
		return iRet;  //encrypt err

	LOG_PRINT_HEX(szEncData, inEncDataLen);	
#endif
	return 0;
}

int inImamAesDecrypt (unsigned char *ucInput, int inInputLen, unsigned char *ucOutput, int *inOutputLen)
{
#ifdef IMAM_AES_OMNI
	LIBENCRYPT cl;
	unsigned char abtKey[32];
	unsigned char szPlainData[TLE_MAX_DATA_SZ];
	int iKeyLen = 0;
	int inPlainDataLen = TLE_MAX_DATA_SZ;
	int iRet = 0;
	
	// Initialize AES library
	AES_Init(MODE_ECB, PAD_NULL_NUM_BYTES, &cl);
	iKeyLen = AES_KEY_LENGTH;
	// Generate Key
	memset(abtKey, 0x00, sizeof(abtKey));
	AES_GenKey ("1234567890123456", abtKey, &iKeyLen);
	LOG_PRINT_HEX(abtKey, iKeyLen);

	// decrypt data
	memset(szPlainData, 0x00, TLE_MAX_DATA_SZ);
	iRet = cl.iDecrypt ((unsigned char *)ucInput, inInputLen, szPlainData, &inPlainDataLen, abtKey, AES_KEY_LENGTH, &cl);
	
	memcpy(ucOutput, szPlainData, inPlainDataLen);
	*inOutputLen = inPlainDataLen;

	if (0 != iRet)
		return iRet;

	LOG_PRINT_HEX(szPlainData, inPlainDataLen);	
#endif
	return 0;
}
#endif

int fImamSale(void) 
{
   char buff[128];
   memset(buff, 0x00, sizeof(buff));
   get_env_x("TRX.SALE", 0, buff);
   if ((atoi(buff)==1) || (!strcmp(buff, "ON"))) return 1;
   return 0;
}

int fImamSSP(void) 
{
   char buff[128];
   memset(buff, 0x00, sizeof(buff));
   get_env_x("TRX.SSP", 0, buff);
   if ((atoi(buff)==1) || (!strcmp(buff, "ON"))) return 1;
   return 0;
}

int fImamOR(void) 
{
   char buff[128];
   memset(buff, 0x00, sizeof(buff));
   get_env_x("TRX.OR", 0, buff);
   if ((atoi(buff)==1) || (!strcmp(buff, "ON"))) return 1;
   return 0;
}

int fImamCardVer(void) 
{
   char buff[128];
   memset(buff, 0x00, sizeof(buff));
   get_env_x("TRX.CARDVER", 0, buff);
   if ((atoi(buff)==1) || (!strcmp(buff, "ON"))) return 1;
   return 0;
}

int fImamPrintCardVer(void) 
{
   char buff[128];
   memset(buff, 0x00, sizeof(buff));
   if (get_env_x("TRX.PRINTCARDVER", 0, buff)) {
	   if ((atoi(buff)==1) || (!strcmp(buff, "ON"))) {
		   return 1;
	   } else {
		   return 0;
	   }
   }
   return 1;
}

int fImamAuthOnly(void) 
{
   char buff[128];
   memset(buff, 0x00, sizeof(buff));
   get_env_x("TRX.AUTHONLY", 0, buff);
   if ((atoi(buff)==1) || (!strcmp(buff, "ON"))) return 1;
   return 0;
}

int fImamNormPreAuth(void) 
{
   char buff[128];
   memset(buff, 0x00, sizeof(buff));
   get_env_x("TRX.NORMPREAUTH", 0, buff);
   if ((atoi(buff)==1) || (!strcmp(buff, "ON"))) return 1;
   return 0;
}

int fImamOffline(void) 
{
   char buff[128];
   memset(buff, 0x00, sizeof(buff));
   get_env_x("TRX.OFFLINE", 0, buff);
   if ((atoi(buff)==1) || (!strcmp(buff, "ON"))) return 1;
   return 0;
}

int fImamRefund(void) 
{
   char buff[128];
   memset(buff, 0x00, sizeof(buff));
   get_env_x("TRX.REFUND", 0, buff);
   if ((atoi(buff)==1) || (!strcmp(buff, "ON"))) return 1;
   return 0;
}

int fImamTipAdjust(void) 
{
   char buff[128];
   memset(buff, 0x00, sizeof(buff));
   get_env_x("TRX.TIP-ADJUST", 0, buff);
   if ((atoi(buff)==1) || (!strcmp(buff, "ON"))) return 1;
   return 0;
}

int fImamTipPrompt(void) 
{
   char buff[128];
   memset(buff, 0x00, sizeof(buff));
   get_env_x("TRX.TIP-PROMPT", 0, buff);
   if ((atoi(buff)==1) || (!strcmp(buff, "ON"))) return 1;
   return 0;
}

int fImamPreAuth(void) 
{
   char buff[128];
   memset(buff, 0x00, sizeof(buff));
   get_env_x("TRX.PREAUTH", 0, buff);
   if ((atoi(buff)==1) || (!strcmp(buff, "ON"))) return 1;
   return 0;
}

int fImamPreComp(void) 
{
   char buff[128];
   memset(buff, 0x00, sizeof(buff));
   get_env_x("TRX.PRECOMP", 0, buff);
   if ((atoi(buff)==1) || (!strcmp(buff, "ON"))) return 1;
   return 0;
}

int inUseSNasTID(void)
{
   char buff[128];
   memset(buff, 0x00, sizeof(buff));
   get_env_x("SN-AS-TID", 0, buff);
   if (atoi(buff)==1) return 1;
   return 0;
}

int inImamEMVFallback(void) 
{
   char buff[128];
   memset(buff, 0x00, sizeof(buff));
   get_env_x("EMV.FALLBACK", 0, buff);
   // if ((atoi(buff)>=1) || (!strcmp(buff, "ON"))) return 1;
   return 0;
}

int inImamEMVFullFallback(void) 
{
   char buff[128];
   memset(buff, 0x00, sizeof(buff));
   get_env_x("EMV.FALLBACK", 0, buff);
   if (atoi(buff)==2) return 1;
   return 0;
}

int inImamEmaMasking(void) 
{
   char buff[128];
   memset(buff, 0x00, sizeof(buff));
   get_env_x("EMA.MASKING", 0, buff);
   return atoi(buff);
}

void DisplayTopLogo(int mode)
{
	char hrf[20];
	char buff[30];
	buff[0] = 0x00; buff[1] = 0x01; buff[2] = 0x02; buff[3] = 0x03;
	buff[4] = 0x04; buff[5] = 0x05; buff[6] = 0x06; buff[7] = 0x07;
	memset(hrf, 0x00, sizeof(hrf));
	get_font(hrf);
	set_font("TopLogo2.vft");
	if (mode) write_at(buff, 8, 1, 1);
	buff[0] = 0x08;
	write_at(buff, 1, 1, inImamLineNumber/2-1);
	set_font(hrf);
}

void ClearTopLogo(int mode)
{
	char hrf[20];
	char buff[30];
	int i;
	if (!mode) return;
	memset(hrf, 0x00, sizeof(hrf));
	get_font(hrf);
	set_font("TopLogo2.vft");
	for (i=0; i<8; i++) buff[i] = 50; //char kosong
	write_at(buff, 8, 1, 1);
	set_font(hrf);
}

int inImamDisplayBatteryLevel(int inBatteryLevel)
{
	char hrf[20];
	char buff[30];

	memset(hrf, 0x00, sizeof(hrf));
	memset(buff, 0x00, sizeof(buff));

	get_font(hrf);
	set_font("F:WifiLogo.vft");

	buff[0]= 12 + inBatteryLevel/10;

	write_at(buff, 1, 1, inImamLineNumber/2-2);
	set_font(hrf);
	return VS_SUCCESS;
}

void DisplayStatusMSG(char *msg)
{
	char buff[30];
	char hrf[20];
	int inMsgLen = strlen(msg);
	if (inMsgLen>21) inMsgLen = 21;

	memset(hrf, 0x00, sizeof(hrf));
	get_font(hrf);

	if (inMsgLen==0) { 
		set_font(ASC8X21_VFT);
		display_at( 1+2, inImamLineNumber,"", CLR_EOL); 
		set_font(hrf);
		return;
	}
	memset(buff, 0x00, sizeof(buff));
	memset(buff, 0x20, 21);
	//strncpy(&buff[(21-strlen(msg))/2], msg, strlen(msg));
	strncpy(buff, msg, inMsgLen);
	//set_font("asc8x21i.vft");
	set_font(ASC8X21_VFT);
	write_at(buff, strlen(buff), 1+2, inImamLineNumber);
	set_font(hrf);
}

void DisplayStatus(char *msg)
{
	char buff[30];
	char hrf[20];
	int inMsgLen = strlen(msg);
	if (inMsgLen>21) inMsgLen = 21;

	memset(hrf, 0x00, sizeof(hrf));
	get_font(hrf);

	if (inMsgLen==0) { 
		set_font(ASC8X21_VFT);
		display_at( 1, inImamLineNumber,"", CLR_EOL); 
		set_font(hrf);
		return;
	}
	memset(buff, 0x00, sizeof(buff));
	memset(buff, 0x20, 21);
	//strncpy(&buff[(21-strlen(msg))/2], msg, strlen(msg));
	strncpy(buff, msg, inMsgLen);
	//set_font("asc8x21i.vft");
	set_font(ASC8X21_VFT);
	write_at(buff, strlen(buff), 1, inImamLineNumber);
	set_font(hrf);
}

void ClearStatusLine(void)
{
	DisplayStatus("");
}

void LOG_PRINT_HEX(unsigned char* buf, int size)
{
	int i;
	char temp[1024*6];
	char cs[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
	
	memset(temp, 0x00, sizeof(temp));
	if ( size>sizeof(temp)/3 ) size = sizeof(temp)/3;
	
	for ( i=0; i<size; i++)
	{
		temp[i*3] 	= cs[ buf[i]>>4 & 0x0F];
		temp[i*3+1] = cs[ buf[i] & 0x0F];
		temp[i*3+2]	= ' ';
	}

	for ( i=0; i<size/10+1; i++)
	{	
		char tt[31];
		memset(tt, '\0', sizeof(tt));
		memcpy(tt, &(temp[i*30]), 30);
		tt[30] = '\0';
		LOG_PRINTFF((0x08L, "(%-2d)->(%s)", i, tt));
	}
}

int get_str_x(char *buffer, int n, char ucSeparator, char *buff)
{
	char bufftmp[128];
	int i, j=0;
	int ni=0;
	int inRetVal = 0;

	memset(bufftmp, 0x00, sizeof(bufftmp));
	strcpy(bufftmp, buffer);
	for (i=0, j=0; (buffer[i]!=0x00); i++) {
		if (buffer[i] == ucSeparator) {
			ni++;
			if (ni==n+1) {
				bufftmp[i] = 0x00;
				break;
			} else {
				j=i+1;
			}
		}
	}
	strcpy(bufftmp, &bufftmp[j]);
	vdTrimSpace(bufftmp);
	strcpy(buff, bufftmp);
	return (inRetVal);
}

int get_env_x(char *param, int n, char *buff)
{
	char buffer[128];
	char bufftmp[128];
	int i, j=0;
	int ni=0;
	int inRetVal = 0;
	memset(buffer, 0x00, sizeof(buffer));

	inRetVal = get_env(param, buffer, sizeof(buffer)-1);
	if (inRetVal>0) {
		//LOG_PRINTFF((0x08L, "get_env_x (%s,%d: %d %s)", param, n, j, buffer));
		for (i=0, j=0; (buffer[i]!=0x00); i++) {
			if (buffer[i] == ';') {
				ni++;
				if (ni==n+1) {
					buffer[i] = 0x00;
					break;
				} else {
					j=i+1;
				}
			}
		}
	}
	memset(bufftmp, 0x00, sizeof(bufftmp));
	strcpy(bufftmp, &buffer[j]);
	vdTrimSpace(bufftmp);
	strcpy(buff, bufftmp);
	LOG_PRINTFF((0x08L, "get_env_x (%s,%d: %d %s)", param, n, j, buff));
	return (inRetVal);
}

int put_env_x(char *param, int n, char *buff)
{
	char buffer[128]; char OrgBuff[128];
	int i, j=0;
	int ni=0;
	memset(buffer, 0x00, sizeof(buffer));
	memset(OrgBuff, 0x00, sizeof(OrgBuff));
	if (get_env(param, buffer, sizeof(buffer)-1)>0) {
		//LOG_PRINTFF((0x08L, "get_env_x (%s,%d: %d %s)", param, n, j, buffer));
		strcpy(OrgBuff, buffer);
		for (i=0, j=0; (buffer[i]!=0x00); i++) {
			if (buffer[i] == ';') {
				ni++;
				if (ni==n+1) {
					buffer[i] = 0x00;
					break;
				} else {
					j=i+1;
				}
			}
		}
	}
    memset(buffer, 0x00, sizeof(buffer));
	strncpy(buffer, OrgBuff, j);
	strcat(buffer, buff);
	strcat(buffer, &OrgBuff[i]);
	LOG_PRINTFF((0x08L, "put_env_x :%s", buffer));
	return put_env(param, buffer, strlen(buffer));
}


void vdScrollDisplay(void)
{
	char hrf[20];

	memset(hrf, 0x00, sizeof(hrf));
	get_font(hrf);
	set_font(ASC8X21_VFT);
	gotoxy(1, 2);
	delline();
	gotoxy(1, inImamLineNumber);
	set_font(hrf);
}

void GetTopDateTime(char *Dest) 
{
	char TimeBuff[20];
	memset(TimeBuff, 0x00, sizeof(TimeBuff));
	SVC_CLOCK(0, TimeBuff, 15);
		
	Dest[0] = TimeBuff[6];
	Dest[1] = TimeBuff[7];
	Dest[2] = '/';
	Dest[3] = TimeBuff[4];
	Dest[4] = TimeBuff[5];
	Dest[5] = '/';
	Dest[6] = TimeBuff[2];
	Dest[7] = TimeBuff[3];
	Dest[8] = 0x20;
	Dest[9] = 0x20;
	Dest[10] = 0x20;
	Dest[11] = TimeBuff[8];
	Dest[12] = TimeBuff[9];
	Dest[13] = ':';
	Dest[14] = TimeBuff[10];
	Dest[15] = TimeBuff[11];
	Dest[16] = 0x00;
}
int inEnablePrintISOTrace(void)
{
   char buff[128];
   memset(buff, 0x00, sizeof(buff));
   get_env_x("ISO-TRACE", 0, buff);
 //  if ((atoi(buff)==1) || (!strcmp(buff, "ON"))) return 1;
   return 0;
}

int InputString(char *Caption, char *Buffer)
{
   char buff[128];
   char hrf[20];

//   char szKeyMap[MAX_ALPNUM_KEYS][CHAR_PER_KEY]= {"0- +%",
//	"1QZ.\\", "2ABC&", "3DEF%", "4GHI*", "5JKL/", "6MNO~",
//	"7PRS^", "8TUV[", "9WXY]", "*,'\":", "#=;$?" };

   char szKeyMap[MAX_ALPNUM_KEYS][6]= {"0- +%",
	"1QZ.\\", "2ABC&", "3DEF%", "4GHI*", "5JKL/", "6MNO~",
	"7PRS^", "8TUV[", "9WXY]", "*,'\":", "#=;$?" };

   memset(buff, 0x00, sizeof(buff));
   memset(hrf, 0x00, sizeof(hrf));

   get_font(hrf);
   set_font(ASC8X21_VFT);
   write_at(Caption, strlen(Caption), 1, inImamLineNumber-1);
   window(strlen(Caption)+1, inImamLineNumber-1, 21, inImamLineNumber-1);
   gotoxy(1, 1); write_at("-", 1, 1, 1);
#ifdef __arm
   if (SVC_KEY_TXT(buff, 1, 16, 1, (char *)szKeyMap, sizeof(szKeyMap)) < 1) {
#elif _TARG_68000
   if (SVC_KEY_TXT(buff, 1, 16, 1, szKeyMap, sizeof(szKeyMap)) < 1) {
#endif
	   window(1, 1, 21, inImamLineNumber);
	   set_font(hrf);
	   return -1;
   }
   window(1, 1, 21, inImamLineNumber);
   buff[buff[0]]=0x00;
   strcpy(Buffer, &buff[1]);
   set_font(hrf);
   return 1;
}

void vdTrimSpace(char *buff)
{
	int i=0;

	for (i=0; buff[i]!=0x00; i++) {
		if (!isspace(buff[i])) {
			strcpy(buff, &buff[i]);
			break;
		}
	}
	while (strlen(buff)) {  //trimspace 
		if (isspace(buff[strlen(buff)-1])) {
			buff[strlen(buff)-1] = 0x00;
		} else {
			break;
		}
	}
}

void vdFormatText(char *buff, int kolom, int Justify)
{
  char buffer[128];
  char buffspace[128];
  memset(buffer, 0x00, sizeof(buffer));
  memset(buffspace, 0x20, sizeof(buffspace));

  if (strlen(buff)>kolom) buff[kolom] = 0x00;
  if (Justify==0) { //Center
	  strncpy(buffer, buffspace, (kolom-strlen(buff))/2);
	  strcat(buffer, buff);
	  strncat(buffer, buffspace, (kolom-strlen(buff))/2);
  } else if (Justify==1) { //R Text
	  strncpy(buffer, buffspace, (kolom-strlen(buff)));
	  strcat(buffer, buff);
  }
  strcpy(buff, buffer);
  buff[kolom] = 0x00;
}



int TimeOut(unsigned long TheTime)
{
	static unsigned long timeout;
	static unsigned long ulAddition = 0L;
	int ret=0;
	if (TheTime!=0) {
		timeout = read_ticks() + TheTime;
		ulAddition = 0L;
		ret=1;
		//return 1;
	} else {
		unsigned long ulCurrTicks = read_ticks(); 
		if (ulCurrTicks>timeout) {
			if (ulAddition==0L) {
				vdWarnBeep();
				ulAddition = 3000L;
				timeout += 3000L;
				//return 0;
				 ret=0;
			}
			//return 1;
			ret=1;
		} else {
		          ret=0;
			//return 0;
		}
	}
	return ret;
}

int inImamTimeOut(unsigned long TheTime)
{
	static unsigned long ulImamTimeout;
		int ret=0;
	if (TheTime > 0) {
		ulImamTimeout = read_ticks() + TheTime;
		    ret=1;
			//return 1;
	} else {
		unsigned long ulCurrTicks = read_ticks(); 
		if (ulCurrTicks>ulImamTimeout) {
			
			    ret=1;
			//return 1;
		} else {
			
			    ret=0;
			//return 0;
		}
	}
	return ret;
}

void ClearSevenLine(void) 
{
	int i;

	set_font(ASC8X21_VFT);
	for (i=0; i<inImamLineNumber-1; i++) {
		gotoxy(1, 2);
		delline();
	}
}


void ClearSixLine(void) 
{
	int i;

	set_font(ASC8X21_VFT);
	for (i=2; i<inImamLineNumber-1; i++) {
		gotoxy(1, 2);
		delline();
	}
}



void DisplayJudul(char *msg)
{
	char buff[30];
	char szFont[30];
	int inMsgLen = strlen(msg);

	if (inMsgLen>21) inMsgLen = 21;
	memset(buff, 0x00, sizeof(buff));
	memset(buff, 0x20, 21);
	memset(szFont, 0x00, sizeof(szFont));
	strncpy(&buff[(21-strlen(msg))/2], msg, inMsgLen);
	get_font(szFont);
	set_font("F:asc8x21i.vft");
	write_at(buff, strlen(buff), 1, 1);
	set_font(szFont);
}

void vdDisplayMerchantName(void)
{
	char hrf[20];
	char buff[128];

	memset(hrf, 0x00, sizeof(hrf));
	memset(buff, 0x00, sizeof(buff));

	strcpy( buff, szGetRctHdr2());	
	//get_env(PRT_HEADER1, buff, sizeof(buff)-1);
	vdTrimSpace(buff);
	if (strlen(buff)) vdFormatText(buff, 16, CENTERED);

	get_font(hrf);
	set_font(ASC8X21_VFT);
	gotoxy(1, 2);
	write_at("                           ", 21, 1, 2);
	set_font(ASC4X16_VFT);
	if (strlen(buff)==16) {write_at(buff, 16, 1, 2);}
	else {display_at(1, 2, buff, CLR_EOL);}
	set_font(hrf);
	set_font(ASC8X21_VFT);
}

int inImamGetString (char *label, char *szStr, long Min, long Max)
{
	if (inNewInputString(label, szStr, Min, Max)<=0) return VS_ERR;
	return VS_SUCCESS;
}

int inNewInputString(char *label, char *Number, long Min, long Max)
{
	int karakter=0;
	long Num;
	char buff[40];
	int inAddLine = 0;
	char szLabel[30];
      int ret=1;
	memset(szLabel, 0x00, sizeof(szLabel));
	strcpy(szLabel, label);
	if (strlen(szLabel)>1 && szLabel[strlen(szLabel)-1] == '-') {
		inAddLine = 1;
		szLabel[strlen(szLabel)-1] = 0x00;
	}

	set_font("");
	display_at(1, inImamLineNumber-1, szLabel, CLR_EOL);
	if (inAddLine) vdScrollDisplay();
	write_at("_", 1, 21, inImamLineNumber-1);
	vdFlushKeyboardBuffer();
	TimeOut(15000);
	do {
		if (KBHIT()) {
			//char buff[20];
			karakter = get_char();
			//sprintf(buff, "%d", karakter);
			//DisplayStatus(buff);
			TimeOut(15000);
		} else {
			if (TimeOut(0)) return 0;
			SVC_WAIT(0);
			continue;
		}
		if ((karakter >= 0x30 && karakter <= 0x39) || (karakter=='*' || karakter=='#')) {
			if ((strlen(Number)<21) && (strlen(Number)<Max)) {
				Number[strlen(Number)] = karakter;
				write_at(Number, strlen(Number), 22-strlen(Number), inImamLineNumber-1);
			}
		} else if (karakter==15 && strlen(Number)>0) {
			int i=0;
			int j=0;
			int found=0;
			for (i=0; i<MAX_ALPNUM_KEYS; i++) {
				for (j=0; j<CHAR_PER_KEY; j++) {
					if (szKeyMap[i][j] == Number[strlen(Number)-1]) {
						j++;
						if (j==4) j=0;
						Number[strlen(Number)-1] = szKeyMap[i][j];
						found=1;
						break;
					}
				}
				if (found) break;
			}
			write_at(Number, strlen(Number), 22-strlen(Number), inImamLineNumber-1);
		} else if (karakter==8) {
			if (strlen(Number)>0) {
				Number[strlen(Number)-1] = 0x00;	
				if (inAddLine) {
					display_at(1, inImamLineNumber-2, szLabel, CLR_EOL);
					display_at(1, inImamLineNumber-1, " ", CLR_EOL);
				} else {
					display_at(1, inImamLineNumber-1, szLabel, CLR_EOL);
				}
				write_at(Number, strlen(Number), 22-strlen(Number), inImamLineNumber-1);
			} else {
				write_at("_", 1, 21, inImamLineNumber-1);
			}
		} else if (karakter==13){
			if (strlen(Number)<Min){
				memset(Number, 0x00, strlen(Number));
				DisplayStatus("Out of range...!");
				vdWarnBeep();
				SVC_WAIT(1000);
				write_at("                     ", 21, 1, inImamLineNumber-1);
				if (inAddLine) {
					write_at(szLabel, strlen(szLabel), 1, inImamLineNumber-2);
				} else {
					write_at(szLabel, strlen(szLabel), 1, inImamLineNumber-1);
				}
				write_at("_", 1, 21, inImamLineNumber-1);
				DisplayStatus("");
			} else {
			         ret=1;
					break;  
				//return 1;
			}
		} else if (karakter==27){
			//return 0;
			 ret=0;
			 break;
			 
		} 
	} while (1);
	return ret;
}

int InputPAN(char *label, char *Number, long Min, long Max, int mode, long *ret)
{
	int karakter=0;
	long Num;
	char buff[40];
       int ret2=1;
	set_font(ASC8X21_VFT);
	write_at(label, strlen(label), 1, inImamLineNumber-1);
	write_at("0", 1, 21, inImamLineNumber-1);
	//vdFlushKeyboardBuffer();
	TimeOut(15000);
	do {
		if (KBHIT()) {
			karakter = get_char();
			TimeOut(15000);
		} else {
			if (TimeOut(0)) return 0;
			SVC_WAIT(0);
			continue;
		}
		if (karakter >= 0x30 && karakter <= 0x39) {
			if (strlen(Number)<21) {
				Number[strlen(Number)] = karakter;
				if (mode==1) {
					memset(buff, 0x00, sizeof(buff));
					FormatNumberEngl(buff, Number);
					write_at(buff, strlen(buff), 22 - strlen(buff), inImamLineNumber-1);
				}else{
					write_at(Number, strlen(Number), 22-strlen(Number), inImamLineNumber-1);
				}
			}
		} else if (karakter==8) {
			if (strlen(Number)>0) {
				Number[strlen(Number)-1] = 0x00;
				display_at(1, inImamLineNumber-1, label, CLR_EOL);
				if (mode==1) {
					memset(buff, 0x00, sizeof(buff));
					FormatNumberEngl(buff, Number);
					write_at(buff, strlen(buff), 22 - strlen(buff), inImamLineNumber-1);
				}else{
					write_at(Number, strlen(Number), 22-strlen(Number), inImamLineNumber-1);
				}
			}
		} else if (karakter==13){
			Num = atol(Number);
			if ((mode==1 || mode==2) && (Num < Min || Num > Max)) {
				memset(Number, 0x00, strlen(Number));
				DisplayStatus("Out of range...!");
				vdWarnBeep();
				SVC_WAIT(1000);
				write_at("                     ", 21, 1, inImamLineNumber-1);
				write_at(label, strlen(label), 1, inImamLineNumber-1);
				write_at("0", 1, 21, inImamLineNumber-1);
				DisplayStatus("");
			} else {
				*ret = Num;
				//return 1;
				ret2=1;
				break;
			}
		} else if (karakter==27){
			//return 0;
			ret2=0;
				break;
		} 
	} while (1);
	return ret2;
}

int InputPIN(char *label, char *Number, int MinChar, int MaxChar)
{
	int karakter=0;
	char szBuff[21];
     int ret2=1;
	memset(szBuff, 0x00, sizeof(szBuff));
	set_font(ASC8X21_VFT);
	vdDisplayAt(1, inImamLineNumber-1, " ", CLR_EOL);
	write_at(label, strlen(label), 1, inImamLineNumber-1);
	DisplayStatus("");

	TimeOut(15000);
	do {
		if (KBHIT()) {
			karakter = get_char();
			TimeOut(15000);
		} else {
			if (TimeOut(0)) 
				return 0;
			SVC_WAIT(0);
			continue;
		}
		if (karakter >= 0x30 && karakter <= 0x39) {
			if (strlen(Number) <= MaxChar) {
				Number[strlen(Number)] = karakter;
				szBuff[strlen(szBuff)] = '*';
				//write_at(Number, strlen(Number), 22-MaxChar, inImamLineNumber-1);
				if (strlen(szBuff)) 
					write_at(szBuff, strlen(szBuff), 22-MaxChar, inImamLineNumber-1);
			}
		} else if (karakter==8) {
			if (strlen(Number)>0) {
				Number[strlen(Number)-1] = 0x00;
				szBuff[strlen(szBuff)-1] = 0x00;
				display_at(1, inImamLineNumber-1, label, CLR_EOL);
				if (strlen(szBuff)) 
					write_at(szBuff, strlen(szBuff), 22-MaxChar, inImamLineNumber-1);
			}
		} else if (karakter==13){
			if (strlen(Number)>= MinChar){
				return 1;
				//ret2=1;
				//break;
			}
		} else if (karakter==27){
			return 0;
			//	ret2=0;
			//	break;
		} 
	} while (1);
	return ret2;
}

//return=0 => cancel
//return=1 => Number entered
//mode==0 => input as string
//mode==1 => input as formated number
//mode==2 => input as unformated number
int InputNumberInd(char *label, char *Number, long Min, long Max, int mode, long *ret)
{
	int karakter=0;
	long Num;
	char buff[40];
	int inAddLine = 0;
	char szLabel[30];
 int ret2=1;
	memset(szLabel, 0x00, sizeof(szLabel));
	strcpy(szLabel, label);
	if (strlen(szLabel)>1 && szLabel[strlen(szLabel)-1] == '-') {
		inAddLine = 1;
		szLabel[strlen(szLabel)-1] = 0x00;
	}

	set_font(ASC8X21_VFT);
	display_at(1, inImamLineNumber-1, szLabel, CLR_EOL);
	if (inAddLine) vdScrollDisplay();
	write_at("0", 1, 21, inImamLineNumber-1);
	vdFlushKeyboardBuffer();
	TimeOut(15000);
	do {
		if (KBHIT()) {
			karakter = get_char();
			TimeOut(15000);
		} else {
			if (TimeOut(0)) return 0;
			SVC_WAIT(0);
			continue;
		}
		if (karakter >= 0x30 && karakter <= 0x39) {
			if (strlen(Number)<21 && ((mode!=3) || (strlen(Number)<Max))) {
				Number[strlen(Number)] = karakter;
				if (mode==1) {
					memset(buff, 0x00, sizeof(buff));
					FormatNumberInd(buff, Number);
					write_at(buff, strlen(buff), 22 - strlen(buff), inImamLineNumber-1);
				}else{
					write_at(Number, strlen(Number), 22-strlen(Number), inImamLineNumber-1);
				}
			}
		} else if (karakter==8) {
			if (strlen(Number)>0) {
				Number[strlen(Number)-1] = 0x00;	
				if (inAddLine) {
					display_at(1, inImamLineNumber-2, szLabel, CLR_EOL);
					display_at(1, inImamLineNumber-1, " ", CLR_EOL);
				} else {
					display_at(1, inImamLineNumber-1, szLabel, CLR_EOL);
				}
				if (mode==1) {
					memset(buff, 0x00, sizeof(buff));
					FormatNumberInd(buff, Number);
					write_at(buff, strlen(buff), 22 - strlen(buff), inImamLineNumber-1);
				}else{
					write_at(Number, strlen(Number), 22-strlen(Number), inImamLineNumber-1);
				}
			}
		} else if (karakter==13){
			Num = atol(Number);
			if (((mode==1 || mode==2) && (Num < Min || Num > Max)) 
				|| (mode==3 && strlen(Number)<Min)){
				memset(Number, 0x00, strlen(Number));
				DisplayStatus("Out of range...!");
				vdWarnBeep();
				SVC_WAIT(1000);
				write_at("                     ", 21, 1, inImamLineNumber-1);
				if (inAddLine) {
					write_at(szLabel, strlen(szLabel), 1, inImamLineNumber-2);
				} else {
					write_at(szLabel, strlen(szLabel), 1, inImamLineNumber-1);
				}
				write_at("0", 1, 21, inImamLineNumber-1);
				DisplayStatus("");
			} else {
				*ret = Num;
				//return 1;
				ret2=1;
				break;
			}
		} else if (karakter==27){

			//return 1;
				ret2=0;
				break;
		} 
	} while (1);
	return ret2;
}

int InputNumberEngl(char *label, char *Number, long Min, long Max, int mode, long *ret)
{
	int karakter=0;
	long Num;
	char buff[40];
	int inAddLine = 0;
	char szLabel[30];
 int ret2=1;
	memset(szLabel, 0x00, sizeof(szLabel));
	strcpy(szLabel, label);
	if (strlen(szLabel)>1 && szLabel[strlen(szLabel)-1] == '-') {
		inAddLine = 1;
		szLabel[strlen(szLabel)-1] = 0x00;
	}

	set_font(ASC8X21_VFT);
	display_at(1, inImamLineNumber-1, szLabel, CLR_EOL);
	if (inAddLine) vdScrollDisplay();
	write_at("0", 1, 21, inImamLineNumber-1);
	vdFlushKeyboardBuffer();
	TimeOut(15000);
	do {
		if (KBHIT()) {
			karakter = get_char();
			TimeOut(15000);
		} else {
			if (TimeOut(0)) return 0;
			SVC_WAIT(0);
			continue;
		}
		if (karakter >= 0x30 && karakter <= 0x39) {
			if (strlen(Number)<21 && ((mode!=3) || (strlen(Number)<Max))) {
				Number[strlen(Number)] = karakter;
				if (mode==1) {
					memset(buff, 0x00, sizeof(buff));
					FormatNumberEngl(buff, Number);
					write_at(buff, strlen(buff), 22 - strlen(buff), inImamLineNumber-1);
				}else{
					write_at(Number, strlen(Number), 22-strlen(Number), inImamLineNumber-1);
				}
			}
		} else if (karakter==8) {
			if (strlen(Number)>0) {
				Number[strlen(Number)-1] = 0x00;	
				if (inAddLine) {
					display_at(1, inImamLineNumber-2, szLabel, CLR_EOL);
					display_at(1, inImamLineNumber-1, " ", CLR_EOL);
				} else {
					display_at(1, inImamLineNumber-1, szLabel, CLR_EOL);
				}
				if (mode==1) {
					memset(buff, 0x00, sizeof(buff));
					FormatNumberEngl(buff, Number);
					write_at(buff, strlen(buff), 22 - strlen(buff), inImamLineNumber-1);
				}else{
					write_at(Number, strlen(Number), 22-strlen(Number), inImamLineNumber-1);
				}
			}
		} else if (karakter==13){
			Num = atol(Number);
			if (((mode==1 || mode==2) && (Num < Min || Num > Max)) 
				|| (mode==3 && strlen(Number)<Min)){
				memset(Number, 0x00, strlen(Number));
				DisplayStatus("Out of range...!");
				vdWarnBeep();
				SVC_WAIT(1000);
				write_at("                     ", 21, 1, inImamLineNumber-1);
				if (inAddLine) {
					write_at(szLabel, strlen(szLabel), 1, inImamLineNumber-2);
				} else {
					write_at(szLabel, strlen(szLabel), 1, inImamLineNumber-1);
				}
				write_at("0", 1, 21, inImamLineNumber-1);
				DisplayStatus("");
			} else {
				*ret = Num;
				//return 1;
				ret2=1;
				break;
			}
		} else if (karakter==27){
			//return 0;
				ret2=0;
				break;
		} 
	} while (1);
	return ret2;
}

int InputNumberWithCentEngl(char *label, char *Number, long Min, long Max, int mode, long *ret)
{
	int karakter=0;
	long Num;
	char buff[40];
  int ret2=1;
	set_font("");
	display_at(1, inImamLineNumber-1, label, CLR_EOL);
	write_at("0", 1, 21, inImamLineNumber-1);
	vdFlushKeyboardBuffer();
	TimeOut(15000);
	do {
		if (KBHIT()) {
			karakter = get_char();
			TimeOut(15000);
		} else {
			if (TimeOut(0)) return 0;
			SVC_WAIT(0);
			continue;
		}
		if (karakter >= 0x30 && karakter <= 0x39) {
			if (strlen(Number)<21 && ((mode!=3) || (strlen(Number)<Max))) {
				Number[strlen(Number)] = karakter;
				if (mode==1) {
					memset(buff, 0x00, sizeof(buff));
					FormatNumberWithCentEngl(buff, Number);
					write_at(buff, strlen(buff), 22 - strlen(buff), inImamLineNumber-1);
				}else{
					write_at(Number, strlen(Number), 22-strlen(Number), inImamLineNumber-1);
				}
			}
		} else if (karakter==8) {
			if (strlen(Number)>0) {
				Number[strlen(Number)-1] = 0x00;
				display_at(1, inImamLineNumber-1, label, CLR_EOL);
				if (mode==1) {
					memset(buff, 0x00, sizeof(buff));
					FormatNumberEngl(buff, Number);
					write_at(buff, strlen(buff), 22 - strlen(buff), inImamLineNumber-1);
				}else{
					write_at(Number, strlen(Number), 22-strlen(Number), inImamLineNumber-1);
				}
			}
		} else if (karakter==13){
			Num = atol(Number);
			if (((mode==1 || mode==2) && (Num < Min || Num > Max)) 
				|| (mode==3 && strlen(Number)<Min)){
				memset(Number, 0x00, strlen(Number));
				DisplayStatus("Out of range...!");
				vdWarnBeep();
				SVC_WAIT(1000);
				write_at("                     ", 21, 1, inImamLineNumber-1);
				write_at(label, strlen(label), 1, inImamLineNumber-1);
				write_at("0", 1, 21, inImamLineNumber-1);
				DisplayStatus("");
			} else {
				*ret = Num;
				//return 1;
				ret2=1;
				break;
			}
		} else if (karakter==27){
			//return 0;
				ret2=0;
				break;
		} 
	} while (1);
	return ret2;
}

void vdGetCurrency(char *szCurr, char *szInput)
{
	char buff[5];
	memset(buff, 0x00, sizeof(buff));
	strncpy(buff, szInput, 3);

	if (!strcmp(buff, "840")) {
		strcpy(szCurr, "US$");
	} else if (!strcmp(buff, "360")) {
		strcpy(szCurr, "RP.");
	} else if (!strcmp(buff, "IDR")) {
		strcpy(szCurr, "RP.");
	} else if (!strcmp(buff, "idr")) {
		strcpy(szCurr, "RP.");
	} else {
		strcpy(szCurr, buff);
	}
}

int FormatNumInd(char *ResBuff, long Number)
{
	char buff[40];
	sprintf(buff, "%ld", Number);
	return FormatNumberInd(ResBuff, buff);
}

int FormatNumberInd(char *ResBuff, char *InpBuff)
{
	char buff[40];
	int i=0;
	int found = 0;

	strcpy(buff, InpBuff);
	for (i=0; buff[i]!=0x00; i++) {
		if (buff[i] != '0') {
			strcpy(buff, &buff[i]);
			break;
		} else {
			found=1;
		}
	}
	if (found==1 && strlen(buff)==strlen(InpBuff)) strcpy(buff, "0");

	if (strlen(buff)>3) {
		strcpy(ResBuff, &buff[strlen(buff)-3]);
		buff[strlen(buff)-3] = 0x00;
	} else {
		strcpy(ResBuff, buff);
		buff[0] = 0x00;
	}

	while (strlen(buff)>0){
		if (strlen(buff)>3) {
			memmove(&ResBuff[4], ResBuff, strlen(ResBuff));
			ResBuff[3] = '.';
			strncpy(ResBuff, &buff[strlen(buff)-3], 3);
			buff[strlen(buff)-3] = 0x00;
		} else {
			memmove(&ResBuff[strlen(buff)+1], ResBuff, strlen(ResBuff));
			ResBuff[strlen(buff)] = '.';
			strncpy(ResBuff, buff, strlen(buff));
			break;
		}
	}
	return 1;
}

int FormatNumberEngl(char *ResBuff, char *InpBuff)
{
	char buff[40];
	int i=0;
	int found = 0;

	strcpy(buff, InpBuff);
	for (i=0; buff[i]!=0x00; i++) {
		if (buff[i] != '0') {
			strcpy(buff, &buff[i]);
			break;
		} else {
			found=1;
		}
	}
	if (found==1 && strlen(buff)==strlen(InpBuff)) strcpy(buff, "0");

	if (strlen(buff)>3) {
		strcpy(ResBuff, &buff[strlen(buff)-3]);
		buff[strlen(buff)-3] = 0x00;
	} else {
		strcpy(ResBuff, buff);
		buff[0] = 0x00;
	}

	while (strlen(buff)>0){
		if (strlen(buff)>3) {
			memmove(&ResBuff[4], ResBuff, strlen(ResBuff));
			ResBuff[3] = ',';
			strncpy(ResBuff, &buff[strlen(buff)-3], 3);
			buff[strlen(buff)-3] = 0x00;
		} else {
			memmove(&ResBuff[strlen(buff)+1], ResBuff, strlen(ResBuff));
			ResBuff[strlen(buff)] = ',';
			strncpy(ResBuff, buff, strlen(buff));
			break;
		}
	}
	return 1;
}

int FormatNumberWithCentInd(char *ResBuff, char *InpBuff)
{
	char buff[40];
	char buff_res[40];
	char Cent[10];

	memset(Cent, 0x00, sizeof(Cent));

	strcpy(buff, InpBuff);
	if (strlen(InpBuff)>=2) {
		buff[strlen(InpBuff)-2] = 0x00;
		strcpy(Cent, &InpBuff[strlen(InpBuff)-2]);
	} else if (strlen(InpBuff)==1){
		buff[0]=0x30;
		Cent[0]=0x30;
		Cent[1]=InpBuff[0];
	} else {
		buff[0]=0x30;
		Cent[0]=0x30;
		Cent[1]=0x30;
	}
	memset(buff_res, 0x00, sizeof(buff_res));
	FormatNumberInd(buff_res, buff);
	sprintf(ResBuff, "%s,%s", buff_res, Cent);

	return 1;
}

int FormatNumberWithCentEngl(char *ResBuff, char *InpBuff)
{
	char buff[40];
	char buff_res[40];
	char Cent[10];

	memset(Cent, 0x00, sizeof(Cent));

	strcpy(buff, InpBuff);
	if (strlen(InpBuff)>=2) {
		buff[strlen(InpBuff)-2] = 0x00;
		strcpy(Cent, &InpBuff[strlen(InpBuff)-2]);
	} else if (strlen(InpBuff)==1){
		buff[0]=0x30;
		Cent[0]=0x30;
		Cent[1]=InpBuff[0];
	} else {
		buff[0]=0x30;
		Cent[0]=0x30;
		Cent[1]=0x30;
	}
	memset(buff_res, 0x00, sizeof(buff_res));
	FormatNumberEngl(buff_res, buff);
	sprintf(ResBuff, "%s.%s", buff_res, Cent);

	return 1;
}

void vdImamFormatDate(char *Dest, char *Date)
{
	char TimeBuff[20];
	memset(TimeBuff, 0x00, sizeof(TimeBuff));
	SVC_CLOCK(0, TimeBuff, 15);
	if (strlen(Date)==8) {
		Dest[0] = Date[6];
		Dest[1] = Date[7];
		Dest[2] = '/';
		Dest[3] = Date[4];
		Dest[4] = Date[5];
		Dest[5] = '/';
		Dest[6] = Date[0];
		Dest[7] = Date[1];
		Dest[8] = Date[2];
		Dest[9] = Date[3];
		Dest[10] = 0x00;
	} else if (strlen(Date)==6) {
		Dest[0] = Date[4];
		Dest[1] = Date[5];
		Dest[2] = '/';
		Dest[3] = Date[2];
		Dest[4] = Date[3];
		Dest[5] = '/';
		Dest[6] = TimeBuff[0];
		Dest[7] = TimeBuff[1];
		Dest[8] = Date[0];
		Dest[9] = Date[1];
		Dest[10] = 0x00;
	} else if (strlen(Date)==4){
		Dest[0] = Date[2];
		Dest[1] = Date[3];
		Dest[2] = '/';
		Dest[3] = Date[0];
		Dest[4] = Date[1];
		Dest[5] = 0x00;
	} else {
		Dest[0] = TimeBuff[6];
		Dest[1] = TimeBuff[7];
		Dest[2] = '/';
		Dest[3] = TimeBuff[4];
		Dest[4] = TimeBuff[5];
		Dest[5] = '/';
		Dest[6] = TimeBuff[0];
		Dest[7] = TimeBuff[1];
		Dest[8] = TimeBuff[2];
		Dest[9] = TimeBuff[3];
		Dest[10] = 0x00;
	}
}

void vdImamFormatTime(char *Dest, char *Time)
{
	char TimeBuff[20];
	memset(TimeBuff, 0x00, sizeof(TimeBuff));
	SVC_CLOCK(0, TimeBuff, 15);
	if (strlen(Time)==6) {
		Dest[0] = Time[0];
		Dest[1] = Time[1];
		Dest[2] = ':';
		Dest[3] = Time[2];
		Dest[4] = Time[3];
		Dest[5] = ':';
		Dest[6] = Time[4];
		Dest[7] = Time[5];
		Dest[8] = 0x00;
	} else {
		Dest[0] = TimeBuff[8];
		Dest[1] = TimeBuff[9];
		Dest[2] = ':';
		Dest[3] = TimeBuff[10];
		Dest[4] = TimeBuff[11];
		Dest[5] = ':';
		Dest[6] = TimeBuff[12];
		Dest[7] = TimeBuff[13];
		Dest[8] = 0x00;
	}
}

void vdMaskNameString(char *buff)
{
	int i=0;
	int inNotSpaceCount = 0;
	if (strlen(buff)==0) return;
	for (i=0; i<strlen(buff); i++) {
		if (!isspace(buff[i])) {
			inNotSpaceCount++;
			if (inNotSpaceCount>=3) {
				buff[i] = '*';
			}
		} else {
			inNotSpaceCount = 0;
		}
	}
}

int inMenuChoice(char *Label, char *MenuItem1, char *MenuItem2, char *MenuItem3, char *MenuItem4)
{
	int i, karakter=0;
	int inMaxStrLen = 0;
	   int ret=0;
	vdFlushKeyboardBuffer();
	ClearSevenLine();

	if (strlen(MenuItem1)>15)	MenuItem1[15] = 0x00;
	if (strlen(MenuItem2)>15)	MenuItem2[15] = 0x00;
	if (strlen(MenuItem3)>15)	MenuItem3[15] = 0x00;
	if (strlen(MenuItem4)>15)	MenuItem4[15] = 0x00;
	if (strlen(Label)>15) Label[15] = 0x00;
	if (strlen(MenuItem1)>inMaxStrLen) inMaxStrLen = strlen(MenuItem1);
	if (strlen(MenuItem2)>inMaxStrLen) inMaxStrLen = strlen(MenuItem2);
	if (strlen(MenuItem3)>inMaxStrLen) inMaxStrLen = strlen(MenuItem3);
	if (strlen(MenuItem4)>inMaxStrLen) inMaxStrLen = strlen(MenuItem4);
	if (strlen(Label)+inMaxStrLen > 20)	Label[20-inMaxStrLen] = 0x00;

	set_font(ASC8X21_VFT);
	for(i=2; i<=inImamLineNumber; i++) write_at("|", 1, 21-inMaxStrLen, i);
	display_at(1,inImamLineNumber-1, Label, NO_CLEAR);
	if (inImamLineNumber == 16){
		display_at(22-strlen(MenuItem1), 4, MenuItem1, NO_CLEAR);
		display_at(22-strlen(MenuItem2), 7, MenuItem2, NO_CLEAR);
		display_at(22-strlen(MenuItem3), 10, MenuItem3, NO_CLEAR);
		display_at(22-strlen(MenuItem4), 13, MenuItem4, NO_CLEAR);
	} else {
		display_at(22-strlen(MenuItem1), 2, MenuItem1, NO_CLEAR);
		display_at(22-strlen(MenuItem2), 4, MenuItem2, NO_CLEAR);
		display_at(22-strlen(MenuItem3), 6, MenuItem3, NO_CLEAR);
		display_at(22-strlen(MenuItem4), 8, MenuItem4, NO_CLEAR);
	}
	set_font(ASC8X21_VFT);

	TimeOut(15000);
	do {
		if (KBHIT()) {
			karakter = get_char();
			TimeOut(15000);
		} else {
			if (TimeOut(0)) return 0;
			SVC_WAIT(0);
			continue;
		}
		if (karakter == 0x01 && strlen(MenuItem1)) {        //F1
			//return 1;
			ret=1;
			break;
		} else if (karakter == 0x02 && strlen(MenuItem2)) { //F2
			//return 2;
			ret=2;
			break;
		} else if (karakter == 0x03 && strlen(MenuItem3)) { //F3
			//return 3;
			ret=3;
			break;
		} else if (karakter == 0x04 && strlen(MenuItem4)) { //F4
			//return 4;
			ret=4;
			break;
		} else if (karakter == 0x1B) { //esc, no choice
			//return 0;
			//return 1;
			ret=0;
			break;
		}
	} while(1);
	return ret;
}

int inHorizontalMenuChoice(char *Label, char *MenuItem1, char *MenuItem2, char *MenuItem3, char *MenuItem4)
{
//#ifndef IMAM_BNI
	int i;
//#endif	
		int karakter=0;
	int inMaxStrLen = 0;
	int retval=0;
	vdFlushKeyboardBuffer();
	ClearStatusLine();

	if (strlen(MenuItem1)>6)	MenuItem1[6] = 0x00;
	if (strlen(MenuItem2)>6)	MenuItem2[6] = 0x00;
	if (strlen(MenuItem3)>6)	MenuItem3[6] = 0x00;
	if (strlen(MenuItem4)>6)	MenuItem4[6] = 0x00;
	if (strlen(Label)>21) Label[21] = 0x00;

	set_font("");
	if (strlen(Label)) display_at(1,inImamLineNumber-1, Label, CLR_EOL);
	set_font("F:asc8x21i.vft");
	if (strlen(MenuItem1)) display_at(1, inImamLineNumber, MenuItem1, NO_CLEAR);
	if (strlen(MenuItem2)) display_at(6, inImamLineNumber, MenuItem2, NO_CLEAR);
	if (strlen(MenuItem3) && !strlen(MenuItem4)) display_at(12, inImamLineNumber, MenuItem3, NO_CLEAR);
	if (strlen(MenuItem4)) {
		if (strlen(MenuItem3)){
			display_at(22-strlen(MenuItem4)-strlen(MenuItem3)-1, inImamLineNumber, MenuItem3, NO_CLEAR);
		}
		display_at(22-strlen(MenuItem4), inImamLineNumber, MenuItem4, NO_CLEAR);
	}

	set_font("");
	TimeOut(15000);
	do {
		if (KBHIT()) {
			karakter = get_char();
			TimeOut(15000);
		} else {
			if (TimeOut(0)) return 0;
			SVC_WAIT(0);
			continue;
		}
		if (karakter == 97 && strlen(MenuItem1)) {        //key_a
			if (strlen(Label)) display_at(22-strlen(MenuItem1), inImamLineNumber-1, MenuItem1, NO_CLEAR);
			//return 1;
			retval=1;
			break;
		} else if (karakter == 98 && strlen(MenuItem2)) { //key_b
			if (strlen(Label)) display_at(22-strlen(MenuItem2), inImamLineNumber-1, MenuItem2, NO_CLEAR);
			//return 2;
			//return 1;
			retval=2;break;
		} else if (karakter == 99 && strlen(MenuItem3)) { //key_c
			if (strlen(Label)) display_at(22-strlen(MenuItem3), inImamLineNumber-1, MenuItem3, NO_CLEAR);
			//return 3;
			//return 1;
			retval=3;break;
		} else if (karakter == 100 && strlen(MenuItem4)) { //key_d
			if (strlen(Label)) display_at(22-strlen(MenuItem4), inImamLineNumber-1, MenuItem4, NO_CLEAR);
			//return 4;
			//return 1;
			retval=4;break;
		} else if (karakter == 0x1B) { //esc, no choice
			//return VS_ERR;
			//return 1;
			retval=VS_ERR;break;
		}
	} while(1);
	return retval;
}

  long lnGetAndIncStanNum(void)
{
	char buffer[128];
	 long InvNum = 0;

	memset(buffer, 0x00, sizeof(buffer));
	get_env_x(IMAM_STAN_NUM, 0, buffer);

	InvNum = atol(buffer);
	if (InvNum) {
		memset(buffer, 0x00, sizeof(buffer));
		if (InvNum==63535L) {
			sprintf(buffer, "%ld", 0L);
		} else {
			sprintf(buffer, "%ld", InvNum+1);
		}
		put_env_x(IMAM_STAN_NUM, 0, buffer);
		return (InvNum);
	}
	return 0;
}

unsigned long ulGetAndIncInvNum(void)
{
	char buffer[128];
	unsigned long InvNum = 0;

	memset(buffer, 0x00, sizeof(buffer));
	get_env_x(IMAM_INV_NUM, 0, buffer);

	InvNum = atol(buffer);
	if (InvNum) {
		memset(buffer, 0x00, sizeof(buffer));
		if (InvNum==999999L) {
			sprintf(buffer, "%ld", 0L);
		} else {
			sprintf(buffer, "%ld", InvNum+1);
		}
		put_env_x(IMAM_INV_NUM, 0, buffer);
		return (InvNum);
	}
	return 0;
}

int inGetPrintTimes(void)
{
	char buffer[128];
	int inPrintTimes = 0;

	memset(buffer, 0x00, sizeof(buffer));
	get_env_x(PRT_COPY, 0, buffer);

	inPrintTimes = atoi(buffer);
	if (inPrintTimes<=0) inPrintTimes = 1;

	return inPrintTimes;
}


void vdImamGetFooter(int inMessageIndex, char* szMessageBuffer) 
{
	if (msg_select_file("F:englfoot.dat") < 0) {
		return;
    }
    if (msg_get(abs(inMessageIndex), szMessageBuffer) == NULL) {
		msg_select_file("");
        return;
    }
	vdTrimSpace(szMessageBuffer);
	msg_select_file("");
}

void vdImamGetEmaBitmap(int inMessageIndex, char* szMessageBuffer) 
{
	if (msg_select_file("F:EmaBMP.dat") < 0) {
		return;
    }
    if (msg_get(abs(inMessageIndex), szMessageBuffer) == NULL) {
		msg_select_file("");
        return;
    }
	vdTrimSpace(szMessageBuffer);
	msg_select_file("");
}

void vdImamGetEmaData(int inMessageIndex, int inToken, char* szMessageBuffer) 
{
	char buffer[128];
	char bufftmp[128];
	int i, j=0;
	int ni=0;
	int inRetVal = 0;
	
	memset(buffer, 0x00, sizeof(buffer));
	if (msg_select_file("F:EmaDATA.dat") < 0) {
		return;
    }
    if (msg_get(abs(inMessageIndex), buffer) == NULL) {
		msg_select_file("");
        return;
    }
	for (i=0, j=0; (buffer[i]!=0x00); i++) {
		if (buffer[i] == ';') {
			ni++;
			if (ni==inToken+1) {
				buffer[i] = 0x00;
				break;
			} else {
				j=i+1;
			}
		}
	}
	memset(bufftmp, 0x00, sizeof(bufftmp));
	strcpy(bufftmp, &buffer[j]);
	strcpy(szMessageBuffer, bufftmp);
	vdTrimSpace(szMessageBuffer);
	msg_select_file("");
	LOG_PRINTFF((0x08L, "vdImamGetEmaData (MSGID[%d], TOKEN[%d]) = [%s]", inMessageIndex, inToken, szMessageBuffer));
}

int inImamFileReadLine(unsigned char *szFileName, int inLine, unsigned char *szBuff)
{
	unsigned char szTmp[2];
	int i = 0;
	int inLineRead = 1;
	int inByteRead = 0;
	int infp = open((char* )szFileName, O_RDONLY);
	memset(szTmp, 0x00, sizeof(szTmp));
	if (infp == -1) return infp;
	do{
		inByteRead = read(infp, (char *)szTmp, 1);
		if (inByteRead != 1) break;
		if (szTmp[0] == '\n') {
			inLineRead++;
			if (inLineRead > inLine) {break;} else {continue;}
		}
		if (inLineRead == inLine) szBuff[i++] = szTmp[0];
	} while (1);
	if (strlen((char *)szBuff)) szBuff[strlen((char *)szBuff)-1] = 0x00; //delete a '\r';
	close(infp);
	return infp;
}

int inImamPowerVxCom1(void)
{
#ifdef __arm
	//const char chPwrOn = COM1_PWR_PIN_ON | COM1_PWR_ON;
	char chPwrOn = COM1_PWR_PIN_ON & COM1_PWR_ON;
	struct Opn_Blk ob = { Rt_1200, Fmt_A7E1, P_char_mode, 0 };
	int hCom1 = 0;

	hCom1 = open(DEV_COM1, 0);
	if (hCom1>0){
		set_opn_blk(hCom1, &ob);
		chPwrOn = COM1_PWR_ON;
		set_com1_pwr(&chPwrOn);
		chPwrOn = COM1_PWR_PIN_ON;
		set_com1_pwr(&chPwrOn);
	}
	SVC_WAIT(5000);
	{
		chPwrOn = 0;
		set_com1_pwr(&chPwrOn);
		close(hCom1);
		hCom1 = 0;
	}
#endif
	return VS_SUCCESS;
}

/*************************************/
// 
#ifndef IMAM_BNI
int iBniSetMKey3D( char * key) 
{ 

	if ((strlen((char *)key))<1)
	return VS_ERR;

	if (((strlen((char *)key))==16) || (strlen((char *)key))==32)
      		put_env_x("TD.MKEY", 0, key);
      	
     return VS_SUCCESS;
	 
}

int iBniSetWKey3D( char *key) 
{ 
	if ((strlen((char *)key))<1)
	return VS_ERR;

	if (((strlen((char *)key))==16) || (strlen((char *)key))==32)
      		put_env_x("TD.WKEY", 0, key);

	  return VS_SUCCESS;
}

#endif
int fImamGetMKey3D(unsigned char *key) 
{ 
	char mkey[33];
	int i=0;
	memset(mkey,0x00,sizeof(mkey));
      get_env_x("TD.MKEY", 0, mkey);
	  strcpy((char *)key,mkey);
	  if (atoi((char *)key) < 1)  return 1;
     return 0;
	 
}

int fImamGetWKey3D(unsigned char *key) 
{ 
char buff[128];

memset(buff,0x00,sizeof(buff));
   get_env_x("TD.WKEY", 0, buff);
   strncpy((char *)key,buff,32);
   if (atoi((char *)key) < 1)  return 1;

   return 0;
}

/*****************************************/
int inImamDES_SD (unsigned char *szKey, unsigned char *szEncData, unsigned char *szResult)
{
	unsigned long k[16][2];
	setkey(k, szKey, 1);
	encrypt(k, szEncData);
	memcpy(szResult, szEncData, 8);
	return 1;
}

int inImamDES_SE (unsigned char *szKey, unsigned char *szClearData, unsigned char *szResult)
{
	unsigned long k[16][2];
	setkey(k, szKey, 0);
	encrypt(k, szClearData);
	memcpy(szResult, szClearData, 8);
	return 1;
}

int inImamDES_DD (unsigned char *szKey, unsigned char *szEncData, unsigned char *szResult)
{
	unsigned long k[16][2];
	setkey(k, szKey, 1);
	encrypt(k, szEncData);
	setkey(k, &szKey[8], 0);
	encrypt(k, szEncData);
	setkey(k, szKey, 1);
	encrypt(k, szEncData);
	memcpy(szResult, szEncData, 8);
	return 1;
}

int inImamDES_DE (unsigned char *szKey, unsigned char *szClearData, unsigned char *szResult)
{
	unsigned long k[16][2];
	setkey(k, szKey, 0);
	encrypt(k, szClearData);
	setkey(k, &szKey[8], 1);
	encrypt(k, szClearData);
	setkey(k, szKey, 0);
	encrypt(k, szClearData);
	memcpy(szResult, szClearData, 8);
	return 1;
}

int inImamDES_TD (unsigned char *szKey, unsigned char *szEncData, unsigned char *szResult)
{
	unsigned long k[16][2];
	setkey(k, &szKey[16], 1);
	encrypt(k, szEncData);
	setkey(k, &szKey[8], 0);
	encrypt(k, szEncData);
	setkey(k, szKey, 1);
	encrypt(k, szEncData);
	memcpy(szResult, szEncData, 8);
	return 1;
}

int inImamDES_TE (unsigned char *szKey, unsigned char *szClearData, unsigned char *szResult)
{
	unsigned long k[16][2];
	setkey(k, szKey, 0);
	encrypt(k, szClearData);
	setkey(k, &szKey[8], 1);
	encrypt(k, szClearData);
	setkey(k, &szKey[16], 0);
	encrypt(k, szClearData);
	memcpy(szResult, szClearData, 8);
	return 1;
}

void setkey(unsigned long k[][2], unsigned char *key, int decrypt)
{
	unsigned char pc1[] = {
		57, 49, 41, 33, 25, 17,  9, 1,  58, 50, 42, 34, 26, 18,
		10,  2, 59, 51, 43, 35, 27, 19, 11,  3, 60, 52, 44, 36,
		63, 55, 47, 39, 31, 23, 15, 7,  62, 54, 46, 38, 30, 22,
		14,  6, 61, 53, 45, 37, 29, 21, 13,  5, 28, 20, 12,  4
	};
	unsigned char totrot[] = {
		1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28
	};
	unsigned char pc2[] = {
		14, 17, 11, 24,  1,  5,  3, 28, 15,  6, 21, 10,
		23, 19, 12,  4, 26,  8, 16,  7, 27, 20, 13,  2,
		41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48,
		44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32
	};
	int bytebit[] = {
		0200,0100,040,020,010,04,02,01
	};

	unsigned char pc1m[56];
	unsigned char pcr[56];
	register int i,j,l;
	int m;
	unsigned char ks[8];

	for (j=0; j<56; j++)
	{
		l=pc1[j]-1;
		m = l & 07;
		pc1m[j]=(key[l>>3] & bytebit[m]) ? 1 : 0;
	}
	for (i=0; i<16; i++)
	{
		memset(ks,0,sizeof(ks));
		for (j=0; j<56; j++)
			pcr[j] = pc1m[(l=j+totrot[decrypt? 15-i : i])<(j<28? 28 : 56) ? l: l-28];
		for (j=0; j<48; j++){
			if (pcr[pc2[j]-1]){
				l= j % 6;
				ks[j/6] |= bytebit[l] >> 2;
			}
		}
		k[i][0] = ((long)ks[0] << 24)
		 | ((long)ks[2] << 16)
		 | ((long)ks[4] << 8)
		 | ((long)ks[6]);
		k[i][1] = ((long)ks[1] << 24)
		 | ((long)ks[3] << 16)
		 | ((long)ks[5] << 8)
		 | ((long)ks[7]);
	}
}

#define	F(l,r,key1,key2){\
		work = ((r >> 4) | (r << 28)) ^ key1;	\
		l ^= Spbox[6][work & 0x3f];		\
		l ^= Spbox[4][(work >> 8) & 0x3f];	\
		l ^= Spbox[2][(work >> 16) & 0x3f];	\
		l ^= Spbox[0][(work >> 24) & 0x3f];	\
		work = r ^ key2;			\
		l ^= Spbox[7][work & 0x3f];		\
		l ^= Spbox[5][(work >> 8) & 0x3f];	\
		l ^= Spbox[3][(work >> 16) & 0x3f];	\
		l ^= Spbox[1][(work >> 24) & 0x3f];	\
}


void encrypt(unsigned long ks[16][2], unsigned char block[8])
{
	unsigned long left, right, work;

	unsigned long Spbox[8][64] = {
0x01010400,0x00000000,0x00010000,0x01010404, 0x01010004,0x00010404,0x00000004,0x00010000,
0x00000400,0x01010400,0x01010404,0x00000400, 0x01000404,0x01010004,0x01000000,0x00000004,
0x00000404,0x01000400,0x01000400,0x00010400, 0x00010400,0x01010000,0x01010000,0x01000404,
0x00010004,0x01000004,0x01000004,0x00010004, 0x00000000,0x00000404,0x00010404,0x01000000,
0x00010000,0x01010404,0x00000004,0x01010000, 0x01010400,0x01000000,0x01000000,0x00000400,
0x01010004,0x00010000,0x00010400,0x01000004, 0x00000400,0x00000004,0x01000404,0x00010404,
0x01010404,0x00010004,0x01010000,0x01000404, 0x01000004,0x00000404,0x00010404,0x01010400,
0x00000404,0x01000400,0x01000400,0x00000000, 0x00010004,0x00010400,0x00000000,0x01010004,
0x80108020,0x80008000,0x00008000,0x00108020, 0x00100000,0x00000020,0x80100020,0x80008020,
0x80000020,0x80108020,0x80108000,0x80000000, 0x80008000,0x00100000,0x00000020,0x80100020,
0x00108000,0x00100020,0x80008020,0x00000000, 0x80000000,0x00008000,0x00108020,0x80100000,
0x00100020,0x80000020,0x00000000,0x00108000, 0x00008020,0x80108000,0x80100000,0x00008020,
0x00000000,0x00108020,0x80100020,0x00100000, 0x80008020,0x80100000,0x80108000,0x00008000,
0x80100000,0x80008000,0x00000020,0x80108020, 0x00108020,0x00000020,0x00008000,0x80000000,
0x00008020,0x80108000,0x00100000,0x80000020, 0x00100020,0x80008020,0x80000020,0x00100020,
0x00108000,0x00000000,0x80008000,0x00008020, 0x80000000,0x80100020,0x80108020,0x00108000,
0x00000208,0x08020200,0x00000000,0x08020008, 0x08000200,0x00000000,0x00020208,0x08000200,
0x00020008,0x08000008,0x08000008,0x00020000, 0x08020208,0x00020008,0x08020000,0x00000208,
0x08000000,0x00000008,0x08020200,0x00000200, 0x00020200,0x08020000,0x08020008,0x00020208,
0x08000208,0x00020200,0x00020000,0x08000208, 0x00000008,0x08020208,0x00000200,0x08000000,
0x08020200,0x08000000,0x00020008,0x00000208, 0x00020000,0x08020200,0x08000200,0x00000000,
0x00000200,0x00020008,0x08020208,0x08000200, 0x08000008,0x00000200,0x00000000,0x08020008,
0x08000208,0x00020000,0x08000000,0x08020208, 0x00000008,0x00020208,0x00020200,0x08000008,
0x08020000,0x08000208,0x00000208,0x08020000, 0x00020208,0x00000008,0x08020008,0x00020200,
0x00802001,0x00002081,0x00002081,0x00000080, 0x00802080,0x00800081,0x00800001,0x00002001,
0x00000000,0x00802000,0x00802000,0x00802081, 0x00000081,0x00000000,0x00800080,0x00800001,
0x00000001,0x00002000,0x00800000,0x00802001, 0x00000080,0x00800000,0x00002001,0x00002080,
0x00800081,0x00000001,0x00002080,0x00800080, 0x00002000,0x00802080,0x00802081,0x00000081,
0x00800080,0x00800001,0x00802000,0x00802081, 0x00000081,0x00000000,0x00000000,0x00802000,
0x00002080,0x00800080,0x00800081,0x00000001, 0x00802001,0x00002081,0x00002081,0x00000080,
0x00802081,0x00000081,0x00000001,0x00002000, 0x00800001,0x00002001,0x00802080,0x00800081,
0x00002001,0x00002080,0x00800000,0x00802001, 0x00000080,0x00800000,0x00002000,0x00802080,
0x00000100,0x02080100,0x02080000,0x42000100, 0x00080000,0x00000100,0x40000000,0x02080000,
0x40080100,0x00080000,0x02000100,0x40080100, 0x42000100,0x42080000,0x00080100,0x40000000,
0x02000000,0x40080000,0x40080000,0x00000000, 0x40000100,0x42080100,0x42080100,0x02000100,
0x42080000,0x40000100,0x00000000,0x42000000, 0x02080100,0x02000000,0x42000000,0x00080100,
0x00080000,0x42000100,0x00000100,0x02000000, 0x40000000,0x02080000,0x42000100,0x40080100,
0x02000100,0x40000000,0x42080000,0x02080100, 0x40080100,0x00000100,0x02000000,0x42080000,
0x42080100,0x00080100,0x42000000,0x42080100, 0x02080000,0x00000000,0x40080000,0x42000000,
0x00080100,0x02000100,0x40000100,0x00080000, 0x00000000,0x40080000,0x02080100,0x40000100,
0x20000010,0x20400000,0x00004000,0x20404010, 0x20400000,0x00000010,0x20404010,0x00400000,
0x20004000,0x00404010,0x00400000,0x20000010, 0x00400010,0x20004000,0x20000000,0x00004010,
0x00000000,0x00400010,0x20004010,0x00004000, 0x00404000,0x20004010,0x00000010,0x20400010,
0x20400010,0x00000000,0x00404010,0x20404000, 0x00004010,0x00404000,0x20404000,0x20000000,
0x20004000,0x00000010,0x20400010,0x00404000, 0x20404010,0x00400000,0x00004010,0x20000010,
0x00400000,0x20004000,0x20000000,0x00004010, 0x20000010,0x20404010,0x00404000,0x20400000,
0x00404010,0x20404000,0x00000000,0x20400010, 0x00000010,0x00004000,0x20400000,0x00404010,
0x00004000,0x00400010,0x20004010,0x00000000, 0x20404000,0x20000000,0x00400010,0x20004010,
0x00200000,0x04200002,0x04000802,0x00000000, 0x00000800,0x04000802,0x00200802,0x04200800,
0x04200802,0x00200000,0x00000000,0x04000002, 0x00000002,0x04000000,0x04200002,0x00000802,
0x04000800,0x00200802,0x00200002,0x04000800, 0x04000002,0x04200000,0x04200800,0x00200002,
0x04200000,0x00000800,0x00000802,0x04200802, 0x00200800,0x00000002,0x04000000,0x00200800,
0x04000000,0x00200800,0x00200000,0x04000802, 0x04000802,0x04200002,0x04200002,0x00000002,
0x00200002,0x04000000,0x04000800,0x00200000, 0x04200800,0x00000802,0x00200802,0x04200800,
0x00000802,0x04000002,0x04200802,0x04200000, 0x00200800,0x00000000,0x00000002,0x04200802,
0x00000000,0x00200802,0x04200000,0x00000800, 0x04000002,0x04000800,0x00000800,0x00200002,
0x10001040,0x00001000,0x00040000,0x10041040, 0x10000000,0x10001040,0x00000040,0x10000000,
0x00040040,0x10040000,0x10041040,0x00041000, 0x10041000,0x00041040,0x00001000,0x00000040,
0x10040000,0x10000040,0x10001000,0x00001040, 0x00041000,0x00040040,0x10040040,0x10041000,
0x00001040,0x00000000,0x00000000,0x10040040, 0x10000040,0x10001000,0x00041040,0x00040000,
0x00041040,0x00040000,0x10041000,0x00001000, 0x00000040,0x10040040,0x00001000,0x00041040,
0x10001000,0x00000040,0x10000040,0x10040000, 0x10040040,0x10000000,0x00040000,0x10001040,
0x00000000,0x10041040,0x00040040,0x10000040, 0x10040000,0x10001000,0x10001040,0x00000000,
0x10041040,0x00041000,0x00041000,0x00001040, 0x00001040,0x00040040,0x10000000,0x10041000,
};

	left = ((unsigned long)block[0] << 24)
	 	| ((unsigned long)block[1] << 16)
	 	| ((unsigned long)block[2] << 8)
	 	| (unsigned long)block[3];
	right = ((unsigned long)block[4] << 24)
	 	| ((unsigned long)block[5] << 16)
	 	| ((unsigned long)block[6] << 8)
	 	| (unsigned long)block[7];

	work = ((left >> 4) ^ right) & 0x0f0f0f0f;
	right ^= work;
	left ^= work << 4;
	work = ((left >> 16) ^ right) & 0xffff;
	right ^= work;
	left ^= work << 16;
	work = ((right >> 2) ^ left) & 0x33333333;
	left ^= work;
	right ^= (work << 2);
	work = ((right >> 8) ^ left) & 0xff00ff;
	left ^= work;
	right ^= (work << 8);
	right = (right << 1) | (right >> 31);
	work = (left ^ right) & 0xaaaaaaaa;
	left ^= work;
	right ^= work;
	left = (left << 1) | (left >> 31);

	F(left,right,ks[0][0],ks[0][1]);
	F(right,left,ks[1][0],ks[1][1]);
	F(left,right,ks[2][0],ks[2][1]);
	F(right,left,ks[3][0],ks[3][1]);
	F(left,right,ks[4][0],ks[4][1]);
	F(right,left,ks[5][0],ks[5][1]);
	F(left,right,ks[6][0],ks[6][1]);
	F(right,left,ks[7][0],ks[7][1]);
	F(left,right,ks[8][0],ks[8][1]);
	F(right,left,ks[9][0],ks[9][1]);
	F(left,right,ks[10][0],ks[10][1]);
	F(right,left,ks[11][0],ks[11][1]);
	F(left,right,ks[12][0],ks[12][1]);
	F(right,left,ks[13][0],ks[13][1]);
	F(left,right,ks[14][0],ks[14][1]);
	F(right,left,ks[15][0],ks[15][1]);

	right = (right << 31) | (right >> 1);
	work = (left ^ right) & 0xaaaaaaaa;
	left ^= work;
	right ^= work;
	left = (left >> 1) | (left  << 31);
	work = ((left >> 8) ^ right) & 0xff00ff;
	right ^= work;
	left ^= work << 8;
	work = ((left >> 2) ^ right) & 0x33333333;
	right ^= work;
	left ^= work << 2;
	work = ((right >> 16) ^ left) & 0xffff;
	left ^= work;
	right ^= work << 16;
	work = ((right >> 4) ^ left) & 0x0f0f0f0f;
	left ^= work;
	right ^= work << 4;
	block[0] = (unsigned char)(right >> 24);
	block[1] = (unsigned char)(right >> 16);
	block[2] = (unsigned char)(right >> 8);
	block[3] = (unsigned char)(right);
	block[4] = (unsigned char)(left >> 24);
	block[5] = (unsigned char)(left >> 16);
	block[6] = (unsigned char)(left >> 8);
	block[7] = (unsigned char)(left);
}

